This notebook contains research on using KNN for the Kidney Graft Genetics Project to predict graft survival.

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- tidyverse 1.3.1 --
√ ggplot2 3.3.5     √ purrr   0.3.4
√ tibble  3.1.6     √ dplyr   1.0.8
√ tidyr   1.2.0     √ stringr 1.4.0
√ readr   2.1.2     √ forcats 0.5.1
-- Conflicts ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::combine()    masks Biobase::combine(), BiocGenerics::combine()
x dplyr::filter()     masks stats::filter()
x dplyr::lag()        masks stats::lag()
x ggplot2::Position() masks BiocGenerics::Position(), base::Position()
library(tuneR)

Attaching package: ‘tuneR’

The following object is masked from ‘package:Biobase’:

    channel

The following object is masked from ‘package:BiocGenerics’:

    normalize
library(devtools)
Loading required package: usethis
library(ggplot2)
library(tsfeatures)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(class)
library(cvTools)
Loading required package: lattice
Loading required package: robustbase

Attaching package: ‘robustbase’

The following object is masked from ‘package:Biobase’:

    rowMedians
library(randomForest)
randomForest 4.7-1
Type rfNews() to see new features/changes/bug fixes.

Attaching package: ‘randomForest’

The following object is masked from ‘package:dplyr’:

    combine

The following object is masked from ‘package:ggplot2’:

    margin

The following object is masked from ‘package:Biobase’:

    combine

The following object is masked from ‘package:BiocGenerics’:

    combine
library(GEOquery) 
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
Setting options('download.file.method.GEOquery'='auto')
Setting options('GEOquery.inmemory.gpl'=FALSE)
library(R.utils)
Warning: package ‘R.utils’ was built under R version 4.1.3
Loading required package: R.oo
Loading required package: R.methodsS3
R.methodsS3 v1.8.1 (2020-08-26 16:20:06 UTC) successfully loaded. See ?R.methodsS3 for help.
R.oo v1.24.0 (2020-08-26 16:11:58 UTC) successfully loaded. See ?R.oo for help.

Attaching package: ‘R.oo’

The following object is masked from ‘package:R.methodsS3’:

    throw

The following objects are masked from ‘package:devtools’:

    check, unload

The following objects are masked from ‘package:methods’:

    getClasses, getMethods

The following objects are masked from ‘package:base’:

    attach, detach, load, save

R.utils v2.11.0 (2021-09-26 08:30:02 UTC) successfully loaded. See ?R.utils for help.

Attaching package: ‘R.utils’

The following object is masked from ‘package:GEOquery’:

    gunzip

The following object is masked from ‘package:tidyr’:

    extract

The following object is masked from ‘package:utils’:

    timestamp

The following objects are masked from ‘package:base’:

    cat, commandArgs, getOption, inherits, isOpen, nullfile, parse, warnings
library(reshape2)

Attaching package: ‘reshape2’

The following object is masked from ‘package:tidyr’:

    smiths
library(limma)

Attaching package: ‘limma’

The following object is masked from ‘package:BiocGenerics’:

    plotMA
library(dplyr)
library(e1071)
Warning: package ‘e1071’ was built under R version 4.1.3
library(DT)
Warning: package ‘DT’ was built under R version 4.1.3
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(viridis)
Warning: package ‘viridis’ was built under R version 4.1.3
Loading required package: viridisLite
library(plotly)
Warning: package ‘plotly’ was built under R version 4.1.3

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(scales)

Attaching package: ‘scales’

The following object is masked from ‘package:viridis’:

    viridis_pal

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor
library(CPOP) #devtools::install_github("sydneybiox/CPOP") #Will take a while to download and requires user input in console
library(matrixStats)
Warning: package ‘matrixStats’ was built under R version 4.1.3

Attaching package: ‘matrixStats’

The following objects are masked from ‘package:robustbase’:

    colMedians, rowMedians

The following object is masked from ‘package:dplyr’:

    count

The following objects are masked from ‘package:Biobase’:

    anyMissing, rowMedians
gse36059 = getGEO("GSE36059")[[1]]
gse48581 = getGEO("GSE48581")[[1]]
gse129166 = getGEO("GSE129166")[[1]]
gse36059_f = fData(gse36059)
gse36059_f
gse48581_f = fData(gse48581)
gse48581_f
gse129166_f = fData(gse129166)
gse129166_f
gse36059_p = pData(gse36059)
gse36059_p
gse48581_p = pData(gse48581)
gse48581_p
gse129166_p = pData(gse129166)
gse129166_p
#Remove Nephrectomy outcomes
gse36059_p = gse36059_p[!(gse36059_p$characteristics_ch1=="diagnosis: Nephrectomy"),]

gse48581_p = gse48581_p[!(gse48581_p$characteristics_ch1=="diagnosis (tcmr, abmr, mixed, non-rejecting, nephrectomy): nephrectomy"),]
#Encodes stable as 0 and rejecting as 1
gse36059_p$diagnosis = ifelse(gse36059_p$characteristics_ch1 == "diagnosis: non-rejecting", 0, 1)
gse48581_p$diagnosis = ifelse(gse48581_p$characteristics_ch1.1 == "diagnosis (tcmr, abmr, mixed, non-rejecting, nephrectomy): non-rejecting", 0, 1)
gse129166_p$diagnosis = ifelse((gse129166_p$characteristics_ch1.1 == "tcmr (no: 0_borderline:1_TCMR:2): 0") & (gse129166_p$characteristics_ch1.2 == "abmr (no: 0_Yes:1): 0"), 0, 1)
#Encodes stable as 0, ABMR as 1, TCMR as 2, Mixed as 3
gse36059_p$exact_diagnosis = ifelse(gse36059_p$characteristics_ch1 == "diagnosis: non-rejecting", 0, ifelse(gse36059_p$characteristics_ch1 =="diagnosis: ABMR", 1, ifelse(gse36059_p$characteristics_ch1 == "diagnosis: TCMR", 2, 3)))

gse48581_p$exact_diagnosis = ifelse(gse48581_p$characteristics_ch1.1 == "diagnosis (tcmr, abmr, mixed, non-rejecting, nephrectomy): non-rejecting", 0, ifelse(gse48581_p$characteristics_ch1.1 =="diagnosis (tcmr, abmr, mixed, non-rejecting, nephrectomy): ABMR", 1, ifelse(gse48581_p$characteristics_ch1.1 == "diagnosis (tcmr, abmr, mixed, non-rejecting, nephrectomy): TCMR", 2, 3)))

gse129166_p$exact_diagnosis = ifelse((gse129166_p$characteristics_ch1.1 == "tcmr (no: 0_borderline:1_TCMR:2): 0") & (gse129166_p$characteristics_ch1.2 == "abmr (no: 0_Yes:1): 0"), 0, ifelse((gse129166_p$characteristics_ch1.1 != "tcmr (no: 0_borderline:1_TCMR:2): 0") & (gse129166_p$characteristics_ch1.2 != "abmr (no: 0_Yes:1): 0"), 3, ifelse((gse129166_p$characteristics_ch1.1 != "tcmr (no: 0_borderline:1_TCMR:2): 0") & (gse129166_p$characteristics_ch1.2 == "abmr (no: 0_Yes:1): 0"), 2, 1)))
gse36059_p
gse48581_p
gse129166_p

Main outcomes are non-rejecting, TCMR (acute T-cell–mediated rejection), ABMR (anti-donor antibody-mediated rejection), and MIXED. Also has nephrectomy.

gse36059_ex = data.frame(t(exprs(gse36059)))
gse36059_ex
gse48581_ex = data.frame(t(exprs(gse48581)))
gse48581_ex
gse129166_ex = data.frame(t(exprs(gse129166)))
gse129166_ex
start = 1
stop = 100
boxplot(gse36059_ex[start:stop])

boxplot(gse48581_ex[start:stop])

boxplot(gse129166_ex[start:stop])

#TODO 
pairwise_preprocess = function(GSE, top_x) {
  exp_GSE = (exprs(GSE))
  Variance = rowVars(as.matrix(exp_GSE))
  Variance = as.data.frame(Variance)
  exp_GSE = as.data.frame(exp_GSE)
  exp_GSE = cbind(exp_GSE, variance = Variance)
  exp_GSE = slice_max(exp_GSE, order_by = Variance, n = top_x)
  exp_GSE = subset(exp_GSE, select = -c(Variance))
  row_names_exp_GSE = rownames(exp_GSE)
  
  return(exp_GSE)
}

pairwise = function(exp_GSE, intersection, transform_type) {
  
  exp_GSE = as.data.frame(t(as.matrix(exp_GSE)))
  exp_GSE = subset(exp_GSE, select = c(intersection))
  
  z = exp_GSE
  
  if (transform_type == "Arc") {
    z = z / max(z)
    z = asin(sqrt(z))
    z = pairwise_col_diff(z) %>% as.matrix()
  }
  else if (transform_type == "Log") {
    z = z + 1
    z = log(z)
  }
  else if (transform_type == "Pair"){
    z = z %>% as.matrix()
    z_pairwise = pairwise_col_diff(z) %>% as.matrix()
    
  }
  
  return(z)
  
}

z1 = pairwise_preprocess(gse36059, 2000)
z2 = pairwise_preprocess(gse48581, 2000)

intersection = intersect(rownames(z1), rownames(z2))

z1_pair = pairwise(z1, intersection, "Log")
z2_pair = pairwise(z2, intersection, "Log")
boxplot(z1_pair[1:50,], ylim = c(0, 4))

# TODO: Export processed code for all datasets
# TODO: Find overlap in features selected in KNN for the different datasets
#CPOP data

## keeping only the 100 most variable genes in my data frame 
exp_GSE36059 = (exprs(gse36059))
Variance = rowVars(as.matrix(exp_GSE36059))
Variance = as.data.frame(Variance)
exp_GSE36059 = as.data.frame(exp_GSE36059)
exp_GSE36059 = cbind(exp_GSE36059, variance = Variance)
exp_GSE36059 = slice_max(exp_GSE36059, order_by = Variance, n = 2000)
exp_GSE36059 = subset(exp_GSE36059, select = -c(Variance))
row_names_exp_GSE36074 = rownames(exp_GSE36059)

exp_GSE48581 = (exprs(gse48581))
Variance = rowVars(as.matrix(exp_GSE48581))
Variance = as.data.frame(Variance)
exp_GSE48581 = as.data.frame(exp_GSE48581)
exp_GSE48581 = cbind(exp_GSE48581, variance = Variance)
exp_GSE48581 = slice_max(exp_GSE48581, order_by = Variance, n = 2000)
exp_GSE48581 = subset(exp_GSE48581, select = -c(Variance))
row_names_exp_GSE48581 = rownames(exp_GSE48581)

exp_GSE129166 = (exprs(gse129166))
Variance = rowVars(as.matrix(exp_GSE129166))
Variance = as.data.frame(Variance)
exp_GSE129166 = as.data.frame(exp_GSE129166)
exp_GSE129166 = cbind(exp_GSE129166, variance = Variance)
exp_GSE129166 = slice_max(exp_GSE129166, order_by = Variance, n = 2000)
exp_GSE129166 = subset(exp_GSE129166, select = -c(Variance))
row_names_exp_GSE129166 = rownames(exp_GSE129166)
# Takes overlap
intersection = intersect(row_names_exp_GSE34748, row_names_exp_GSE46474)
intersection = intersect(intersection, row_names_exp_GSE129166)

exp_GSE34748 = as.data.frame(t(as.matrix(exp_GSE34748)))
exp_GSE34748 = subset(exp_GSE34748, select = c(intersection))

exp_GSE46474 = as.data.frame(t(as.matrix(exp_GSE46474)))
exp_GSE46474 = subset(exp_GSE46474, select = c(intersection))

exp_GSE129166 = as.data.frame(t(as.matrix(exp_GSE129166)))
exp_GSE129166 = subset(exp_GSE129166, select = c(intersection))

GSE34748_id <- data.frame("Dataset" = rep("GSE34748",nrow(exp_GSE34748)))
GSE46474_id <- data.frame("Dataset" = rep("GSE46474",nrow(exp_GSE46474)))
GSE129166_id <- data.frame("Dataset" = rep("GSE129166",nrow(exp_GSE129166)))

z1 = exp_GSE34748 %>% as.matrix()
z2 = exp_GSE46474 %>% as.matrix()
z3 = exp_GSE129166 %>% as.matrix()

## arcsine transformation

exp_GSE34748_arc <- exp_GSE34748
exp_GSE34748_arc = exp_GSE34748_arc / max(exp_GSE34748_arc)
exp_GSE34748_arc = asin(sqrt(exp_GSE34748_arc))

exp_GSE46474_arc <- exp_GSE46474
exp_GSE46474_arc = exp_GSE46474_arc / max(exp_GSE46474_arc)
exp_GSE46474_arc = asin(sqrt(exp_GSE46474_arc))

exp_GSE129166_arc <- exp_GSE129166
exp_GSE129166_arc = exp_GSE129166_arc / max(exp_GSE129166_arc)
exp_GSE129166_arc = asin(sqrt(exp_GSE129166_arc))

z1_pairwise = pairwise_col_diff(z1) %>% as.matrix()
z2_pairwise = pairwise_col_diff(z2) %>% as.matrix()
z3_pairwise = pairwise_col_diff(z3) %>% as.matrix()


z1_arc = pairwise_col_diff(exp_GSE34748_arc) %>% as.matrix()
z2_arc = pairwise_col_diff(exp_GSE46474_arc) %>% as.matrix()
z3_arc = pairwise_col_diff(exp_GSE129166_arc) %>% as.matrix()

## log transform

exp_GSE34748_log <- exp_GSE34748
exp_GSE34748_log = exp_GSE34748_log + 1
exp_GSE34748_log = log(exp_GSE34748_log)

exp_GSE46474_log <- exp_GSE46474
exp_GSE46474_log = exp_GSE46474_log + 1
exp_GSE46474_log = log(exp_GSE46474_log)

exp_GSE129166_log <- exp_GSE129166
exp_GSE129166_log = exp_GSE129166_log + 1
exp_GSE129166_log = log(exp_GSE129166_log)

z1_log = pairwise_col_diff(exp_GSE34748_log) %>% as.matrix()
z2_log = pairwise_col_diff(exp_GSE46474_log) %>% as.matrix()
z3_log = pairwise_col_diff(exp_GSE129166_log) %>% as.matrix()

pre transformation plot

box11 = cbind(boxplot_tbl(z1, index = 1), GSE34748_id)
box22 = cbind(boxplot_tbl(z2, index = 1), GSE46474_id)
box33 = cbind(boxplot_tbl(z3, index = 1), GSE129166_id)
box4 = rbind(box11, box22, box33)

expressionplot <-
ggplot(data = box4, aes(x = object, y = means)) +
  geom_point(aes(color = Dataset), size = 0.1) +
  geom_errorbar(aes(ymin = q1,
                    ymax = q3,
                    color = Dataset), size = 0.1,  alpha = 0.2) +
  ggsci::scale_color_d3() +
  theme(axis.ticks = element_blank()) +
  theme(axis.text.x = element_blank()) +
  theme(axis.title.x=element_blank()) +
  theme(axis.title.y=element_blank()) +
  ylim(0,15) + 
  theme(legend.position="bottom") +
  theme(legend.title = element_blank()) +
  labs(title = "Raw Data") +
  theme(plot.title = element_text(size=10))

expressionplot

Boxplot to visualise if the arc transformations were good

box1_arc = cbind(boxplot_tbl(z1_arc, index = 1), GSE34748_id)
box2_arc = cbind(boxplot_tbl(z2_arc, index = 1), GSE46474_id)
box3_arc = cbind(boxplot_tbl(z3_arc, index = 1), GSE129166_id)
box4_arc = rbind(box1_arc, box2_arc, box3_arc)

arcplot <-
ggplot(data = box4_arc, aes(x = object, y = means)) +
  geom_point(aes(color = Dataset), size = 0.1) +
  geom_errorbar(aes(ymin = q1,
                    ymax = q3,
                    color = Dataset), size = 0.1,  alpha = 0.2) +
  ggsci::scale_color_d3() +
  theme(axis.ticks = element_blank()) +
  theme(axis.text.x = element_blank()) +
  xlab("Samples") +
  theme(axis.title.y=element_blank()) +
  labs(title = "Arcsine transformation + pairwise difference") +
  theme(plot.title = element_text(size=10))

arcplot

boxplot to see if the log transformation was good

box1_log = cbind(boxplot_tbl(z1_log, index = 1), GSE34748_id)
box2_log = cbind(boxplot_tbl(z2_log, index = 1), GSE46474_id)
box3_log = cbind(boxplot_tbl(z3_log, index = 1), GSE129166_id)
box4_log = rbind(box1_log, box2_log, box3_log)

logplot <-
ggplot(data = box4_log, aes(x = object, y = means)) +
  geom_point(aes(color = Dataset), size = 0.1) +
  geom_errorbar(aes(ymin = q1,
                    ymax = q3,
                    color = Dataset), size = 0.1,  alpha = 0.2) +
  ggsci::scale_color_d3() +
  theme(axis.ticks = element_blank()) +
  theme(axis.text.x = element_blank()) +
  xlab("Samples") +
  theme(axis.title.y=element_blank()) +
  labs(title = "Log transformation + pairwise difference") +
  theme(plot.title = element_text(size=10))

logplot

getting the results vectors

pData(GSE46474)
pData(GSE129166) #is there rejection and stable
pData(GSE34748) #no reject or stable



### GSE36059
### GSE48581
# these have reject + stable but categorized in more detail -> either have more groups that we are predicting, or we could do purely binary 
LS0tDQp0aXRsZTogIktOTiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClRoaXMgbm90ZWJvb2sgY29udGFpbnMgcmVzZWFyY2ggb24gdXNpbmcgS05OIGZvciB0aGUgS2lkbmV5IEdyYWZ0IEdlbmV0aWNzIFByb2plY3QgdG8gcHJlZGljdCBncmFmdCBzdXJ2aXZhbC4NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodHVuZVIpDQpsaWJyYXJ5KGRldnRvb2xzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0c2ZlYXR1cmVzKQ0KbGlicmFyeShjbGFzcykNCmxpYnJhcnkoY3ZUb29scykNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KbGlicmFyeShHRU9xdWVyeSkgDQpsaWJyYXJ5KFIudXRpbHMpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShsaW1tYSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGUxMDcxKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkodmlyaWRpcykNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KENQT1ApICNkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInN5ZG5leWJpb3gvQ1BPUCIpICNXaWxsIHRha2UgYSB3aGlsZSB0byBkb3dubG9hZCBhbmQgcmVxdWlyZXMgdXNlciBpbnB1dCBpbiBjb25zb2xlDQpsaWJyYXJ5KG1hdHJpeFN0YXRzKQ0KYGBgDQoNCmBgYHtyfQ0KZ3NlMzYwNTkgPSBnZXRHRU8oIkdTRTM2MDU5IilbWzFdXQ0KZ3NlNDg1ODEgPSBnZXRHRU8oIkdTRTQ4NTgxIilbWzFdXQ0KZ3NlMTI5MTY2ID0gZ2V0R0VPKCJHU0UxMjkxNjYiKVtbMV1dDQpgYGANCg0KDQoNCmBgYHtyfQ0KZ3NlMzYwNTlfZiA9IGZEYXRhKGdzZTM2MDU5KQ0KZ3NlMzYwNTlfZg0KZ3NlNDg1ODFfZiA9IGZEYXRhKGdzZTQ4NTgxKQ0KZ3NlNDg1ODFfZg0KZ3NlMTI5MTY2X2YgPSBmRGF0YShnc2UxMjkxNjYpDQpnc2UxMjkxNjZfZg0KYGBgDQoNCmBgYHtyfQ0KZ3NlMzYwNTlfcCA9IHBEYXRhKGdzZTM2MDU5KQ0KZ3NlMzYwNTlfcA0KZ3NlNDg1ODFfcCA9IHBEYXRhKGdzZTQ4NTgxKQ0KZ3NlNDg1ODFfcA0KZ3NlMTI5MTY2X3AgPSBwRGF0YShnc2UxMjkxNjYpDQpnc2UxMjkxNjZfcA0KYGBgDQpgYGB7cn0NCiNSZW1vdmUgTmVwaHJlY3RvbXkgb3V0Y29tZXMNCmdzZTM2MDU5X3AgPSBnc2UzNjA1OV9wWyEoZ3NlMzYwNTlfcCRjaGFyYWN0ZXJpc3RpY3NfY2gxPT0iZGlhZ25vc2lzOiBOZXBocmVjdG9teSIpLF0NCg0KZ3NlNDg1ODFfcCA9IGdzZTQ4NTgxX3BbIShnc2U0ODU4MV9wJGNoYXJhY3RlcmlzdGljc19jaDE9PSJkaWFnbm9zaXMgKHRjbXIsIGFibXIsIG1peGVkLCBub24tcmVqZWN0aW5nLCBuZXBocmVjdG9teSk6IG5lcGhyZWN0b215IiksXQ0KYGBgDQoNCg0KYGBge3J9DQojRW5jb2RlcyBzdGFibGUgYXMgMCBhbmQgcmVqZWN0aW5nIGFzIDENCmdzZTM2MDU5X3AkZGlhZ25vc2lzID0gaWZlbHNlKGdzZTM2MDU5X3AkY2hhcmFjdGVyaXN0aWNzX2NoMSA9PSAiZGlhZ25vc2lzOiBub24tcmVqZWN0aW5nIiwgMCwgMSkNCmdzZTQ4NTgxX3AkZGlhZ25vc2lzID0gaWZlbHNlKGdzZTQ4NTgxX3AkY2hhcmFjdGVyaXN0aWNzX2NoMS4xID09ICJkaWFnbm9zaXMgKHRjbXIsIGFibXIsIG1peGVkLCBub24tcmVqZWN0aW5nLCBuZXBocmVjdG9teSk6IG5vbi1yZWplY3RpbmciLCAwLCAxKQ0KZ3NlMTI5MTY2X3AkZGlhZ25vc2lzID0gaWZlbHNlKChnc2UxMjkxNjZfcCRjaGFyYWN0ZXJpc3RpY3NfY2gxLjEgPT0gInRjbXIgKG5vOiAwX2JvcmRlcmxpbmU6MV9UQ01SOjIpOiAwIikgJiAoZ3NlMTI5MTY2X3AkY2hhcmFjdGVyaXN0aWNzX2NoMS4yID09ICJhYm1yIChubzogMF9ZZXM6MSk6IDAiKSwgMCwgMSkNCmBgYA0KDQoNCmBgYHtyfQ0KI0VuY29kZXMgc3RhYmxlIGFzIDAsIEFCTVIgYXMgMSwgVENNUiBhcyAyLCBNaXhlZCBhcyAzDQpnc2UzNjA1OV9wJGV4YWN0X2RpYWdub3NpcyA9IGlmZWxzZShnc2UzNjA1OV9wJGNoYXJhY3RlcmlzdGljc19jaDEgPT0gImRpYWdub3Npczogbm9uLXJlamVjdGluZyIsIDAsIGlmZWxzZShnc2UzNjA1OV9wJGNoYXJhY3RlcmlzdGljc19jaDEgPT0iZGlhZ25vc2lzOiBBQk1SIiwgMSwgaWZlbHNlKGdzZTM2MDU5X3AkY2hhcmFjdGVyaXN0aWNzX2NoMSA9PSAiZGlhZ25vc2lzOiBUQ01SIiwgMiwgMykpKQ0KDQpnc2U0ODU4MV9wJGV4YWN0X2RpYWdub3NpcyA9IGlmZWxzZShnc2U0ODU4MV9wJGNoYXJhY3RlcmlzdGljc19jaDEuMSA9PSAiZGlhZ25vc2lzICh0Y21yLCBhYm1yLCBtaXhlZCwgbm9uLXJlamVjdGluZywgbmVwaHJlY3RvbXkpOiBub24tcmVqZWN0aW5nIiwgMCwgaWZlbHNlKGdzZTQ4NTgxX3AkY2hhcmFjdGVyaXN0aWNzX2NoMS4xID09ImRpYWdub3NpcyAodGNtciwgYWJtciwgbWl4ZWQsIG5vbi1yZWplY3RpbmcsIG5lcGhyZWN0b215KTogQUJNUiIsIDEsIGlmZWxzZShnc2U0ODU4MV9wJGNoYXJhY3RlcmlzdGljc19jaDEuMSA9PSAiZGlhZ25vc2lzICh0Y21yLCBhYm1yLCBtaXhlZCwgbm9uLXJlamVjdGluZywgbmVwaHJlY3RvbXkpOiBUQ01SIiwgMiwgMykpKQ0KDQpnc2UxMjkxNjZfcCRleGFjdF9kaWFnbm9zaXMgPSBpZmVsc2UoKGdzZTEyOTE2Nl9wJGNoYXJhY3RlcmlzdGljc19jaDEuMSA9PSAidGNtciAobm86IDBfYm9yZGVybGluZToxX1RDTVI6Mik6IDAiKSAmIChnc2UxMjkxNjZfcCRjaGFyYWN0ZXJpc3RpY3NfY2gxLjIgPT0gImFibXIgKG5vOiAwX1llczoxKTogMCIpLCAwLCBpZmVsc2UoKGdzZTEyOTE2Nl9wJGNoYXJhY3RlcmlzdGljc19jaDEuMSAhPSAidGNtciAobm86IDBfYm9yZGVybGluZToxX1RDTVI6Mik6IDAiKSAmIChnc2UxMjkxNjZfcCRjaGFyYWN0ZXJpc3RpY3NfY2gxLjIgIT0gImFibXIgKG5vOiAwX1llczoxKTogMCIpLCAzLCBpZmVsc2UoKGdzZTEyOTE2Nl9wJGNoYXJhY3RlcmlzdGljc19jaDEuMSAhPSAidGNtciAobm86IDBfYm9yZGVybGluZToxX1RDTVI6Mik6IDAiKSAmIChnc2UxMjkxNjZfcCRjaGFyYWN0ZXJpc3RpY3NfY2gxLjIgPT0gImFibXIgKG5vOiAwX1llczoxKTogMCIpLCAyLCAxKSkpDQpgYGANCg0KDQpgYGB7cn0NCmdzZTM2MDU5X3ANCmdzZTQ4NTgxX3ANCmdzZTEyOTE2Nl9wDQpgYGANCk1haW4gb3V0Y29tZXMgYXJlIG5vbi1yZWplY3RpbmcsIFRDTVIgKGFjdXRlIFQtY2VsbOKAk21lZGlhdGVkIHJlamVjdGlvbiksIEFCTVIgKGFudGktZG9ub3IgYW50aWJvZHktbWVkaWF0ZWQgcmVqZWN0aW9uKSwgYW5kIE1JWEVELiBBbHNvIGhhcyBuZXBocmVjdG9teS4NCg0KDQpgYGB7cn0NCmdzZTM2MDU5X2V4ID0gZGF0YS5mcmFtZSh0KGV4cHJzKGdzZTM2MDU5KSkpDQpnc2UzNjA1OV9leA0KZ3NlNDg1ODFfZXggPSBkYXRhLmZyYW1lKHQoZXhwcnMoZ3NlNDg1ODEpKSkNCmdzZTQ4NTgxX2V4DQpnc2UxMjkxNjZfZXggPSBkYXRhLmZyYW1lKHQoZXhwcnMoZ3NlMTI5MTY2KSkpDQpnc2UxMjkxNjZfZXgNCmBgYA0KYGBge3J9DQpzdGFydCA9IDENCnN0b3AgPSAxMDANCmJveHBsb3QoZ3NlMzYwNTlfZXhbc3RhcnQ6c3RvcF0pDQpib3hwbG90KGdzZTQ4NTgxX2V4W3N0YXJ0OnN0b3BdKQ0KYm94cGxvdChnc2UxMjkxNjZfZXhbc3RhcnQ6c3RvcF0pDQpgYGANCg0KYGBge3J9DQojVE9ETyANCnBhaXJ3aXNlX3ByZXByb2Nlc3MgPSBmdW5jdGlvbihHU0UsIHRvcF94KSB7DQogIGV4cF9HU0UgPSAoZXhwcnMoR1NFKSkNCiAgVmFyaWFuY2UgPSByb3dWYXJzKGFzLm1hdHJpeChleHBfR1NFKSkNCiAgVmFyaWFuY2UgPSBhcy5kYXRhLmZyYW1lKFZhcmlhbmNlKQ0KICBleHBfR1NFID0gYXMuZGF0YS5mcmFtZShleHBfR1NFKQ0KICBleHBfR1NFID0gY2JpbmQoZXhwX0dTRSwgdmFyaWFuY2UgPSBWYXJpYW5jZSkNCiAgZXhwX0dTRSA9IHNsaWNlX21heChleHBfR1NFLCBvcmRlcl9ieSA9IFZhcmlhbmNlLCBuID0gdG9wX3gpDQogIGV4cF9HU0UgPSBzdWJzZXQoZXhwX0dTRSwgc2VsZWN0ID0gLWMoVmFyaWFuY2UpKQ0KICByb3dfbmFtZXNfZXhwX0dTRSA9IHJvd25hbWVzKGV4cF9HU0UpDQogIA0KICByZXR1cm4oZXhwX0dTRSkNCn0NCg0KcGFpcndpc2UgPSBmdW5jdGlvbihleHBfR1NFLCBpbnRlcnNlY3Rpb24sIHRyYW5zZm9ybV90eXBlKSB7DQogIA0KICBleHBfR1NFID0gYXMuZGF0YS5mcmFtZSh0KGFzLm1hdHJpeChleHBfR1NFKSkpDQogIGV4cF9HU0UgPSBzdWJzZXQoZXhwX0dTRSwgc2VsZWN0ID0gYyhpbnRlcnNlY3Rpb24pKQ0KICANCiAgeiA9IGV4cF9HU0UNCiAgDQogIGlmICh0cmFuc2Zvcm1fdHlwZSA9PSAiQXJjIikgew0KICAgIHogPSB6IC8gbWF4KHopDQogICAgeiA9IGFzaW4oc3FydCh6KSkNCiAgICB6ID0gcGFpcndpc2VfY29sX2RpZmYoeikgJT4lIGFzLm1hdHJpeCgpDQogIH0NCiAgZWxzZSBpZiAodHJhbnNmb3JtX3R5cGUgPT0gIkxvZyIpIHsNCiAgICB6ID0geiArIDENCiAgICB6ID0gbG9nKHopDQogIH0NCiAgZWxzZSBpZiAodHJhbnNmb3JtX3R5cGUgPT0gIlBhaXIiKXsNCiAgICB6ID0geiAlPiUgYXMubWF0cml4KCkNCiAgICB6X3BhaXJ3aXNlID0gcGFpcndpc2VfY29sX2RpZmYoeikgJT4lIGFzLm1hdHJpeCgpDQogICAgDQogIH0NCiAgDQogIHJldHVybih6KQ0KICANCn0NCg0KejEgPSBwYWlyd2lzZV9wcmVwcm9jZXNzKGdzZTM2MDU5LCAyMDAwKQ0KejIgPSBwYWlyd2lzZV9wcmVwcm9jZXNzKGdzZTQ4NTgxLCAyMDAwKQ0KDQppbnRlcnNlY3Rpb24gPSBpbnRlcnNlY3Qocm93bmFtZXMoejEpLCByb3duYW1lcyh6MikpDQoNCnoxX3BhaXIgPSBwYWlyd2lzZSh6MSwgaW50ZXJzZWN0aW9uLCAiTG9nIikNCnoyX3BhaXIgPSBwYWlyd2lzZSh6MiwgaW50ZXJzZWN0aW9uLCAiTG9nIikNCg0KYGBgDQpgYGB7cn0NCmJveHBsb3QoejFfcGFpclsxOjUwLF0sIHlsaW0gPSBjKDAsIDQpKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgVE9ETzogRXhwb3J0IHByb2Nlc3NlZCBjb2RlIGZvciBhbGwgZGF0YXNldHMNCg0KYGBgDQoNCmBgYHtyfQ0KIyBUT0RPOiBGaW5kIG92ZXJsYXAgaW4gZmVhdHVyZXMgc2VsZWN0ZWQgaW4gS05OIGZvciB0aGUgZGlmZmVyZW50IGRhdGFzZXRzDQpgYGANCg0KDQpgYGB7cn0NCiNDUE9QIGRhdGENCg0KIyMga2VlcGluZyBvbmx5IHRoZSAxMDAgbW9zdCB2YXJpYWJsZSBnZW5lcyBpbiBteSBkYXRhIGZyYW1lIA0KZXhwX0dTRTM2MDU5ID0gKGV4cHJzKGdzZTM2MDU5KSkNClZhcmlhbmNlID0gcm93VmFycyhhcy5tYXRyaXgoZXhwX0dTRTM2MDU5KSkNClZhcmlhbmNlID0gYXMuZGF0YS5mcmFtZShWYXJpYW5jZSkNCmV4cF9HU0UzNjA1OSA9IGFzLmRhdGEuZnJhbWUoZXhwX0dTRTM2MDU5KQ0KZXhwX0dTRTM2MDU5ID0gY2JpbmQoZXhwX0dTRTM2MDU5LCB2YXJpYW5jZSA9IFZhcmlhbmNlKQ0KZXhwX0dTRTM2MDU5ID0gc2xpY2VfbWF4KGV4cF9HU0UzNjA1OSwgb3JkZXJfYnkgPSBWYXJpYW5jZSwgbiA9IDIwMDApDQpleHBfR1NFMzYwNTkgPSBzdWJzZXQoZXhwX0dTRTM2MDU5LCBzZWxlY3QgPSAtYyhWYXJpYW5jZSkpDQpyb3dfbmFtZXNfZXhwX0dTRTM2MDc0ID0gcm93bmFtZXMoZXhwX0dTRTM2MDU5KQ0KDQpleHBfR1NFNDg1ODEgPSAoZXhwcnMoZ3NlNDg1ODEpKQ0KVmFyaWFuY2UgPSByb3dWYXJzKGFzLm1hdHJpeChleHBfR1NFNDg1ODEpKQ0KVmFyaWFuY2UgPSBhcy5kYXRhLmZyYW1lKFZhcmlhbmNlKQ0KZXhwX0dTRTQ4NTgxID0gYXMuZGF0YS5mcmFtZShleHBfR1NFNDg1ODEpDQpleHBfR1NFNDg1ODEgPSBjYmluZChleHBfR1NFNDg1ODEsIHZhcmlhbmNlID0gVmFyaWFuY2UpDQpleHBfR1NFNDg1ODEgPSBzbGljZV9tYXgoZXhwX0dTRTQ4NTgxLCBvcmRlcl9ieSA9IFZhcmlhbmNlLCBuID0gMjAwMCkNCmV4cF9HU0U0ODU4MSA9IHN1YnNldChleHBfR1NFNDg1ODEsIHNlbGVjdCA9IC1jKFZhcmlhbmNlKSkNCnJvd19uYW1lc19leHBfR1NFNDg1ODEgPSByb3duYW1lcyhleHBfR1NFNDg1ODEpDQoNCmV4cF9HU0UxMjkxNjYgPSAoZXhwcnMoZ3NlMTI5MTY2KSkNClZhcmlhbmNlID0gcm93VmFycyhhcy5tYXRyaXgoZXhwX0dTRTEyOTE2NikpDQpWYXJpYW5jZSA9IGFzLmRhdGEuZnJhbWUoVmFyaWFuY2UpDQpleHBfR1NFMTI5MTY2ID0gYXMuZGF0YS5mcmFtZShleHBfR1NFMTI5MTY2KQ0KZXhwX0dTRTEyOTE2NiA9IGNiaW5kKGV4cF9HU0UxMjkxNjYsIHZhcmlhbmNlID0gVmFyaWFuY2UpDQpleHBfR1NFMTI5MTY2ID0gc2xpY2VfbWF4KGV4cF9HU0UxMjkxNjYsIG9yZGVyX2J5ID0gVmFyaWFuY2UsIG4gPSAyMDAwKQ0KZXhwX0dTRTEyOTE2NiA9IHN1YnNldChleHBfR1NFMTI5MTY2LCBzZWxlY3QgPSAtYyhWYXJpYW5jZSkpDQpyb3dfbmFtZXNfZXhwX0dTRTEyOTE2NiA9IHJvd25hbWVzKGV4cF9HU0UxMjkxNjYpDQpgYGANCg0KYGBge3J9DQojIFRha2VzIG92ZXJsYXANCmludGVyc2VjdGlvbiA9IGludGVyc2VjdChyb3dfbmFtZXNfZXhwX0dTRTM0NzQ4LCByb3dfbmFtZXNfZXhwX0dTRTQ2NDc0KQ0KaW50ZXJzZWN0aW9uID0gaW50ZXJzZWN0KGludGVyc2VjdGlvbiwgcm93X25hbWVzX2V4cF9HU0UxMjkxNjYpDQoNCmV4cF9HU0UzNDc0OCA9IGFzLmRhdGEuZnJhbWUodChhcy5tYXRyaXgoZXhwX0dTRTM0NzQ4KSkpDQpleHBfR1NFMzQ3NDggPSBzdWJzZXQoZXhwX0dTRTM0NzQ4LCBzZWxlY3QgPSBjKGludGVyc2VjdGlvbikpDQoNCmV4cF9HU0U0NjQ3NCA9IGFzLmRhdGEuZnJhbWUodChhcy5tYXRyaXgoZXhwX0dTRTQ2NDc0KSkpDQpleHBfR1NFNDY0NzQgPSBzdWJzZXQoZXhwX0dTRTQ2NDc0LCBzZWxlY3QgPSBjKGludGVyc2VjdGlvbikpDQoNCmV4cF9HU0UxMjkxNjYgPSBhcy5kYXRhLmZyYW1lKHQoYXMubWF0cml4KGV4cF9HU0UxMjkxNjYpKSkNCmV4cF9HU0UxMjkxNjYgPSBzdWJzZXQoZXhwX0dTRTEyOTE2Niwgc2VsZWN0ID0gYyhpbnRlcnNlY3Rpb24pKQ0KDQpHU0UzNDc0OF9pZCA8LSBkYXRhLmZyYW1lKCJEYXRhc2V0IiA9IHJlcCgiR1NFMzQ3NDgiLG5yb3coZXhwX0dTRTM0NzQ4KSkpDQpHU0U0NjQ3NF9pZCA8LSBkYXRhLmZyYW1lKCJEYXRhc2V0IiA9IHJlcCgiR1NFNDY0NzQiLG5yb3coZXhwX0dTRTQ2NDc0KSkpDQpHU0UxMjkxNjZfaWQgPC0gZGF0YS5mcmFtZSgiRGF0YXNldCIgPSByZXAoIkdTRTEyOTE2NiIsbnJvdyhleHBfR1NFMTI5MTY2KSkpDQoNCnoxID0gZXhwX0dTRTM0NzQ4ICU+JSBhcy5tYXRyaXgoKQ0KejIgPSBleHBfR1NFNDY0NzQgJT4lIGFzLm1hdHJpeCgpDQp6MyA9IGV4cF9HU0UxMjkxNjYgJT4lIGFzLm1hdHJpeCgpDQoNCiMjIGFyY3NpbmUgdHJhbnNmb3JtYXRpb24NCg0KZXhwX0dTRTM0NzQ4X2FyYyA8LSBleHBfR1NFMzQ3NDgNCmV4cF9HU0UzNDc0OF9hcmMgPSBleHBfR1NFMzQ3NDhfYXJjIC8gbWF4KGV4cF9HU0UzNDc0OF9hcmMpDQpleHBfR1NFMzQ3NDhfYXJjID0gYXNpbihzcXJ0KGV4cF9HU0UzNDc0OF9hcmMpKQ0KDQpleHBfR1NFNDY0NzRfYXJjIDwtIGV4cF9HU0U0NjQ3NA0KZXhwX0dTRTQ2NDc0X2FyYyA9IGV4cF9HU0U0NjQ3NF9hcmMgLyBtYXgoZXhwX0dTRTQ2NDc0X2FyYykNCmV4cF9HU0U0NjQ3NF9hcmMgPSBhc2luKHNxcnQoZXhwX0dTRTQ2NDc0X2FyYykpDQoNCmV4cF9HU0UxMjkxNjZfYXJjIDwtIGV4cF9HU0UxMjkxNjYNCmV4cF9HU0UxMjkxNjZfYXJjID0gZXhwX0dTRTEyOTE2Nl9hcmMgLyBtYXgoZXhwX0dTRTEyOTE2Nl9hcmMpDQpleHBfR1NFMTI5MTY2X2FyYyA9IGFzaW4oc3FydChleHBfR1NFMTI5MTY2X2FyYykpDQoNCnoxX3BhaXJ3aXNlID0gcGFpcndpc2VfY29sX2RpZmYoejEpICU+JSBhcy5tYXRyaXgoKQ0KejJfcGFpcndpc2UgPSBwYWlyd2lzZV9jb2xfZGlmZih6MikgJT4lIGFzLm1hdHJpeCgpDQp6M19wYWlyd2lzZSA9IHBhaXJ3aXNlX2NvbF9kaWZmKHozKSAlPiUgYXMubWF0cml4KCkNCg0KDQp6MV9hcmMgPSBwYWlyd2lzZV9jb2xfZGlmZihleHBfR1NFMzQ3NDhfYXJjKSAlPiUgYXMubWF0cml4KCkNCnoyX2FyYyA9IHBhaXJ3aXNlX2NvbF9kaWZmKGV4cF9HU0U0NjQ3NF9hcmMpICU+JSBhcy5tYXRyaXgoKQ0KejNfYXJjID0gcGFpcndpc2VfY29sX2RpZmYoZXhwX0dTRTEyOTE2Nl9hcmMpICU+JSBhcy5tYXRyaXgoKQ0KDQojIyBsb2cgdHJhbnNmb3JtDQoNCmV4cF9HU0UzNDc0OF9sb2cgPC0gZXhwX0dTRTM0NzQ4DQpleHBfR1NFMzQ3NDhfbG9nID0gZXhwX0dTRTM0NzQ4X2xvZyArIDENCmV4cF9HU0UzNDc0OF9sb2cgPSBsb2coZXhwX0dTRTM0NzQ4X2xvZykNCg0KZXhwX0dTRTQ2NDc0X2xvZyA8LSBleHBfR1NFNDY0NzQNCmV4cF9HU0U0NjQ3NF9sb2cgPSBleHBfR1NFNDY0NzRfbG9nICsgMQ0KZXhwX0dTRTQ2NDc0X2xvZyA9IGxvZyhleHBfR1NFNDY0NzRfbG9nKQ0KDQpleHBfR1NFMTI5MTY2X2xvZyA8LSBleHBfR1NFMTI5MTY2DQpleHBfR1NFMTI5MTY2X2xvZyA9IGV4cF9HU0UxMjkxNjZfbG9nICsgMQ0KZXhwX0dTRTEyOTE2Nl9sb2cgPSBsb2coZXhwX0dTRTEyOTE2Nl9sb2cpDQoNCnoxX2xvZyA9IHBhaXJ3aXNlX2NvbF9kaWZmKGV4cF9HU0UzNDc0OF9sb2cpICU+JSBhcy5tYXRyaXgoKQ0KejJfbG9nID0gcGFpcndpc2VfY29sX2RpZmYoZXhwX0dTRTQ2NDc0X2xvZykgJT4lIGFzLm1hdHJpeCgpDQp6M19sb2cgPSBwYWlyd2lzZV9jb2xfZGlmZihleHBfR1NFMTI5MTY2X2xvZykgJT4lIGFzLm1hdHJpeCgpDQoNCg0KYGBgDQoNCiMjIHByZSB0cmFuc2Zvcm1hdGlvbiBwbG90DQpgYGB7cn0NCmJveDExID0gY2JpbmQoYm94cGxvdF90YmwoejEsIGluZGV4ID0gMSksIEdTRTM0NzQ4X2lkKQ0KYm94MjIgPSBjYmluZChib3hwbG90X3RibCh6MiwgaW5kZXggPSAxKSwgR1NFNDY0NzRfaWQpDQpib3gzMyA9IGNiaW5kKGJveHBsb3RfdGJsKHozLCBpbmRleCA9IDEpLCBHU0UxMjkxNjZfaWQpDQpib3g0ID0gcmJpbmQoYm94MTEsIGJveDIyLCBib3gzMykNCg0KZXhwcmVzc2lvbnBsb3QgPC0NCmdncGxvdChkYXRhID0gYm94NCwgYWVzKHggPSBvYmplY3QsIHkgPSBtZWFucykpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBEYXRhc2V0KSwgc2l6ZSA9IDAuMSkgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gcTEsDQogICAgICAgICAgICAgICAgICAgIHltYXggPSBxMywNCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBEYXRhc2V0KSwgc2l6ZSA9IDAuMSwgIGFscGhhID0gMC4yKSArDQogIGdnc2NpOjpzY2FsZV9jb2xvcl9kMygpICsNCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpKSArDQogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCkpICsNCiAgeWxpbSgwLDE1KSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnModGl0bGUgPSAiUmF3IERhdGEiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMCkpDQoNCmV4cHJlc3Npb25wbG90DQpgYGANCg0KIyMgQm94cGxvdCB0byB2aXN1YWxpc2UgaWYgdGhlIGFyYyB0cmFuc2Zvcm1hdGlvbnMgd2VyZSBnb29kDQpgYGB7cn0NCmJveDFfYXJjID0gY2JpbmQoYm94cGxvdF90YmwoejFfYXJjLCBpbmRleCA9IDEpLCBHU0UzNDc0OF9pZCkNCmJveDJfYXJjID0gY2JpbmQoYm94cGxvdF90YmwoejJfYXJjLCBpbmRleCA9IDEpLCBHU0U0NjQ3NF9pZCkNCmJveDNfYXJjID0gY2JpbmQoYm94cGxvdF90YmwoejNfYXJjLCBpbmRleCA9IDEpLCBHU0UxMjkxNjZfaWQpDQpib3g0X2FyYyA9IHJiaW5kKGJveDFfYXJjLCBib3gyX2FyYywgYm94M19hcmMpDQoNCmFyY3Bsb3QgPC0NCmdncGxvdChkYXRhID0gYm94NF9hcmMsIGFlcyh4ID0gb2JqZWN0LCB5ID0gbWVhbnMpKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gRGF0YXNldCksIHNpemUgPSAwLjEpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IHExLA0KICAgICAgICAgICAgICAgICAgICB5bWF4ID0gcTMsDQogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gRGF0YXNldCksIHNpemUgPSAwLjEsICBhbHBoYSA9IDAuMikgKw0KICBnZ3NjaTo6c2NhbGVfY29sb3JfZDMoKSArDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgeGxhYigiU2FtcGxlcyIpICsNCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHRpdGxlID0gIkFyY3NpbmUgdHJhbnNmb3JtYXRpb24gKyBwYWlyd2lzZSBkaWZmZXJlbmNlIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQ0KDQphcmNwbG90DQpgYGANCg0KIyMgYm94cGxvdCB0byBzZWUgaWYgdGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiB3YXMgZ29vZA0KYGBge3J9DQpib3gxX2xvZyA9IGNiaW5kKGJveHBsb3RfdGJsKHoxX2xvZywgaW5kZXggPSAxKSwgR1NFMzQ3NDhfaWQpDQpib3gyX2xvZyA9IGNiaW5kKGJveHBsb3RfdGJsKHoyX2xvZywgaW5kZXggPSAxKSwgR1NFNDY0NzRfaWQpDQpib3gzX2xvZyA9IGNiaW5kKGJveHBsb3RfdGJsKHozX2xvZywgaW5kZXggPSAxKSwgR1NFMTI5MTY2X2lkKQ0KYm94NF9sb2cgPSByYmluZChib3gxX2xvZywgYm94Ml9sb2csIGJveDNfbG9nKQ0KDQpsb2dwbG90IDwtDQpnZ3Bsb3QoZGF0YSA9IGJveDRfbG9nLCBhZXMoeCA9IG9iamVjdCwgeSA9IG1lYW5zKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IERhdGFzZXQpLCBzaXplID0gMC4xKSArDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBxMSwNCiAgICAgICAgICAgICAgICAgICAgeW1heCA9IHEzLA0KICAgICAgICAgICAgICAgICAgICBjb2xvciA9IERhdGFzZXQpLCBzaXplID0gMC4xLCAgYWxwaGEgPSAwLjIpICsNCiAgZ2dzY2k6OnNjYWxlX2NvbG9yX2QzKCkgKw0KICB0aGVtZShheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIHhsYWIoIlNhbXBsZXMiKSArDQogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyh0aXRsZSA9ICJMb2cgdHJhbnNmb3JtYXRpb24gKyBwYWlyd2lzZSBkaWZmZXJlbmNlIikgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQ0KDQpsb2dwbG90DQpgYGANCiMjIGdldHRpbmcgdGhlIHJlc3VsdHMgdmVjdG9ycyANCmBgYHtyfQ0KcERhdGEoR1NFNDY0NzQpDQpwRGF0YShHU0UxMjkxNjYpICNpcyB0aGVyZSByZWplY3Rpb24gYW5kIHN0YWJsZQ0KcERhdGEoR1NFMzQ3NDgpICNubyByZWplY3Qgb3Igc3RhYmxlDQoNCg0KDQojIyMgR1NFMzYwNTkNCiMjIyBHU0U0ODU4MQ0KIyB0aGVzZSBoYXZlIHJlamVjdCArIHN0YWJsZSBidXQgY2F0ZWdvcml6ZWQgaW4gbW9yZSBkZXRhaWwgLT4gZWl0aGVyIGhhdmUgbW9yZSBncm91cHMgdGhhdCB3ZSBhcmUgcHJlZGljdGluZywgb3Igd2UgY291bGQgZG8gcHVyZWx5IGJpbmFyeSANCmBgYA==